import 'package:dio/dio.dart';
import 'package:dio_log/dio_log.dart';
import 'package:x3_base_core/base_utils/base_utils.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
import 'package:x3_base_core/base_utils/base_dio_code_util.dart';
import 'package:x3_base_core/base_utils/base_transform_util.dart';
import 'package:x3_base_core/base_enums/base_http_method_enum.dart';
import 'package:x3_base_core/base_models/base_http_result_model.dart';
import 'package:x3_base_core/base_models/base_http_request_model.dart';
import 'package:x3_base_core/base_utils/base_form_transform_util.dart';
import 'package:x3_base_core/base_models/base_http_response_model.dart';
import 'package:x3_base_core/base_interceptors/base_headers_interceptor.dart';
import 'package:x3_base_core/base_interceptors/base_response_interceptor.dart';

Map<int, dynamic> errorCode = {
  400: '错误请求,请求参数有误',
  401: '未授权，访问被拒绝',
  402: '需要付费',
  403: '身份认证已失效,请重新登陆',
  404: '未找到，服务器找不到指定的资源，文档不存在',
  405: '方法不允许，请求方法（GET、POST、HEAD、Delete、PUT、TRACE等）对指定的资源不适用，用来访问本页面的 HTTP 谓词不被允许（方法不被允许）',
  406: '不接受，请求的资源的内容特性无法满足请求头中的条件，因而无法生成响应实体',
  407: '需要代理认证，与401响应类似，只不过客户端必须在代理服务器上进行身份验证。代理服务器必须返回一个 Proxy-Authenticate 用以进行身份询问',
  408: '请求超时，客户端没有在服务器预备等待的时间内完成一个请求的发送。客户端可以随时再次提交这一请求而无需进行任何更改',
  409: '冲突，通常和PUT请求有关。由于请求和资源的当前状态相冲突，因此请求不能成功',
  410: '失败，被请求的资源在服务器上已经不再可用，而且没有任何已知的转发地址。这样的状况应当被认为是永久性的',
  411: '需要长度，服务器拒绝在没有定义 Content-Length 头的情况下接受请求',
  412: '前提条件失败，服务器在验证在请求的头字段中给出先决条件时，没能满足其中的一个或多个',
  413: '请求实体太长，服务器拒绝处理当前请求，因为该请求提交的实体数据大小超过了服务器愿意或者能够处理的范围',
  414: '请求URI太长，请求的URI 长度超过了服务器能够解释的长度',
  501: '页眉指定了未实现的配置，服务器不支持当前请求所需要的某个功能',
  502: '网关失败，作为网关或者代理工作的服务器尝试执行请求时，从上游服务器接收到无效的响应',
  503: '服务不可用，服务器由于维护或者负载过重未能应答',
  504: '网关超时，作为网关或者代理工作的服务器尝试执行请求时，未能及时从上游服务器或者辅助服务器收到响应',
  505: '服务器不支持请求中所指明的HTTP版本',
};

class BaseDioUtil {
  static Dio _dio = new Dio();

  BaseDioUtil() {
    _dio.interceptors.add(BaseHeadersInterceptor());
    _dio.interceptors.add(DioLogInterceptor());
    _dio.interceptors.add(BaseResponseInterceptor());
  }

  /// 请求服务
  Future<BaseHttpResultModel> fetch(String path, {dynamic params = const {}, Map<String, dynamic> headers, BaseHttpMethodEnum method = BaseHttpMethodEnum.POST, bool showToast = true}) async {
    String optionsMethod = BaseTransformUtil.enumToString(method);
    resultError(DioError e) {
      Response errorResponse;
      if (e.response != null) {
        errorResponse = e.response;
      } else {
        errorResponse = new Response(statusCode: 1000, requestOptions: null);
      }
      if (e.type == DioErrorType.receiveTimeout || e.type == DioErrorType.receiveTimeout) {
        errorResponse.statusCode = BaseDioCodeUtil.network_timeout_code;
      }
      String message;
      String errorId;
      String errorData;
      if (errorResponse.data == null) {
        message = e.message;
      } else {
        if (errorCode.containsKey(errorResponse.statusCode)) {
          message = errorCode[errorResponse.statusCode];
        } else {
          if (errorResponse.data is Map) {
            message = errorResponse.data['message'];
            errorId = errorResponse.data['errorId'];
            errorData = errorResponse.data['errorData'];
          }
          if (errorResponse.data is String) {
            message = errorResponse.data;
          }
        }
      }
      return new BaseHttpResultModel(errorResponse.statusCode, false, BaseDioCodeUtil.sendError(errorResponse.statusCode, message, showToast), errorId, errorData);
    }

    Map<String, dynamic> header = new Map();

    /// 获取头部
    if (headers != null) header.addAll(headers);
    Options options = new Options();

    /// 写入请求
    options.method = optionsMethod;

    /// 写入请求头部
    options.headers = header;
    String service = (method == BaseHttpMethodEnum.GET || method == BaseHttpMethodEnum.DELETE) ? BaseTransformUtil.matchServiceUrl(path, params) : path;
    Response response;
    try {
      response = await _dio.request(BaseUtils.handlerServicePath(service), data: params, options: options);
    } on DioError catch (error) {
      return resultError(error);
    }
    if (response.data is DioError) {
      return resultError(response.data);
    }
    return response.data;
  }

  /// 获取通用入参
  Future<List<BaseHttpRequestModel>> fetchRequestParams(String appApiUrlId) async {
    const String service = '/x3-service-archives-center/archive/v1/request/get/list';
    BaseHttpResultModel result = await fetch(service, params: {'appApiUrlId': appApiUrlId}, method: BaseHttpMethodEnum.POST);
    if (result.code == BaseDioCodeUtil.success_code) {
      List<BaseHttpRequestModel> requests = BaseFormTransformUtil.transformToListRequestData(result.data);
      return Future.value(requests);
    }
    return Future.value([]);
  }

  /// 获取通用出参
  Future<List<BaseHttpResponseModel>> fetchResponseParams(String appApiUrlId) async {
    const String service = '/x3-service-archives-center/archive/user/v1/response/get/list';
    BaseHttpResultModel result = await fetch(service, params: {'appApiUrlId': appApiUrlId}, method: BaseHttpMethodEnum.POST);
    if (result.code == BaseDioCodeUtil.success_code) {
      List<BaseHttpResponseModel> responses = BaseTransformUtil.transformToListResponseData(result.data);
      return Future.value(responses);
    }
    return Future.value([]);
  }

  /// 通用上传
  Future<BaseHttpResultModel> fetchUploadFile(String filePath, {String serviceUrl}) async {
    var name = filePath.substring(filePath.lastIndexOf("/") + 1, filePath.length);
    FormData formData = FormData.fromMap({"file": await MultipartFile.fromFile(filePath, filename: name), 'fileType': 1});
    String service = (serviceUrl != null && serviceUrl.isNotEmpty) ? serviceUrl : '/x3-service-ftp-center/ftp/v2';
    return fetch(service, params: formData, method: BaseHttpMethodEnum.POST);
  }

  /// 批量上传
  Future<List<dynamic>> fetchBatchUploadFile(List<AssetEntity> assetEntityList, {String serviceUrl, bool relativePath = false, bool splitPaths = false}) async {
    String service = (serviceUrl != null && serviceUrl.isNotEmpty) ? serviceUrl : '/x3-service-ftp-center/ftp/v4';
    List<String> filePaths = await BaseUtils.filterAssetEntity(assetEntityList: assetEntityList, fn: (file, int) => file.path);
    List<MultipartFile> files = filePaths.map((path) {
      String fileName = path.substring(path.lastIndexOf("/") + 1, path.length);
      return MultipartFile.fromFileSync(path, filename: fileName);
    }).toList();
    List<MapEntry<String, MultipartFile>> _filesList = files.map((e) => MapEntry<String, MultipartFile>('file', e)).toList();
    FormData formData = FormData();
    formData.files.addAll(_filesList);
    formData.fields.add(MapEntry('fileType', '1'));
    BaseHttpResultModel result = await dioUtil.fetch(service, params: formData, method: BaseHttpMethodEnum.POST);
    if (result.success == false) {
      BaseUtils.showToast('上传失败');
      return [];
    }
    Map<String, dynamic> data = result.data;
    String fileSource = BaseUtils.getKeyData(data, 'fileSource').toString();
    List<dynamic> paths = BaseUtils.getKeyData(data, 'fileRealPaths', defaultValue: []);
    if (relativePath && !splitPaths) return paths;
    if (splitPaths) {
      List<Map<String, dynamic>> fileList = [];
      paths.asMap().keys.forEach((index) {
        Map<String, dynamic> fileItem = {'fileName': files[index].filename, 'fileSource': fileSource, 'fileRealPaths': paths[index], 'fileUrl': fileSource + paths[index]};
        fileList.add(fileItem);
      });
      return fileList;
    }
    List<dynamic> urls = paths.map((path) => fileSource + path).toList();
    return urls;
  }

  /// 批量上传视频
  Future<List<dynamic>> fetchBatchUploadVideoFile(List<AssetEntity> assetEntityList, {bool relativePath = false, bool splitPaths = false}) async {
    String service = '/x3-service-ftp-center/oss/upload';
    List<String> filePaths = await BaseUtils.filterAssetEntity(assetEntityList: assetEntityList, fn: (file, int) => file.path);
    List<MultipartFile> files = filePaths.map((path) {
      String fileName = path.substring(path.lastIndexOf("/") + 1, path.length);
      return MultipartFile.fromFileSync(path, filename: fileName);
    }).toList();
    List<MapEntry<String, MultipartFile>> _filesList = files.map((e) => MapEntry<String, MultipartFile>('file', e)).toList();
    FormData formData = FormData();
    formData.files.addAll(_filesList);
    BaseHttpResultModel result = await dioUtil.fetch(service, params: formData, method: BaseHttpMethodEnum.POST);
    if (result.success == false) {
      BaseUtils.showToast('上传失败');
      return [];
    }
    Map<String, dynamic> data = result.data;
    String fileSource = BaseUtils.getKeyData(data, 'fileSource').toString();
    List<dynamic> paths = BaseUtils.getKeyData(data, 'fileRealPaths', defaultValue: []);
    List<dynamic> urls = paths.map((path) => fileSource + path).toList();
    if (relativePath && !splitPaths) return paths;
    if (splitPaths) {
      List<Map<String, dynamic>> fileList = [];
      paths.asMap().keys.forEach((index) {
        Map<String, dynamic> fileItem = {'fileName': files[index].filename, 'fileSource': fileSource, 'fileRealPaths': paths[index], 'fileUrl': fileSource + paths[index]};
        fileList.add(fileItem);
      });
      return fileList;
    }
    return urls;
  }
}

BaseDioUtil dioUtil = new BaseDioUtil();
